#include "postprocess/common/postprocess_id_generator.h"

#include <algorithm>
#include <array>
#include <cstdint>
#include <iostream>
#include <vector>

PostProcessIdGenerator& PostProcessIdGenerator::GetInstance() noexcept {
  static PostProcessIdGenerator instance;
  return instance;
}

PostProcessIdGenerator::PostProcessIdGenerator() noexcept
    : is_id_used_{std::make_shared<std::array<bool, kMaxId>>()},
      id_queue_{std::make_shared<std::deque<std::uint16_t>>()},
      is_init_(false) {}

void PostProcessIdGenerator::Init() noexcept {
  if (is_init_) return;
  is_id_used_->at(0) = true;
  for (std::uint16_t i{1U}; i < kMaxId; ++i) {
    id_queue_->emplace_back(static_cast<std::uint16_t>(i));
    is_id_used_->at(i) = false;
  }
  is_init_ = true;
}

std::uint16_t PostProcessIdGenerator::GetId() noexcept(false) {
  // std::cout << "[Msg] IdGenerator::GetId()  000000000" << std::endl;
  // std::unique_lock<std::mutex> l(mutex_);
  // mutex_.lock();
  // std::cout << "[Msg] IdGenerator::GetId()  0" << std::endl;
  if (id_queue_->empty()) {
    // std::cout << "IdGenerator::GetId() is 0" << std::endl;
    throw std::runtime_error("IdGenerator: No ID is Avaliable!");
    // return 0;
  }
  // std::cout << "[Msg] IdGenerator::GetId()   1" << std::endl;
  std::uint16_t id{id_queue_->front()};

  // std::cout << "[Msg] IdGenerator::GetId()   2   , id = " << id << std::endl;
  is_id_used_->at(id) = true;
  id_queue_->pop_front();
  // mutex_.unlock();
  return id;
}

bool PostProcessIdGenerator::IsIdUsed(std::uint16_t id) const noexcept {
  return is_id_used_->at(id);
}

void PostProcessIdGenerator::ReleaseId(std::uint16_t id) noexcept(false) {
  // std::cout << "[Msg] IdGenerator::ReleaseId() 00 id = " << id << std::endl;
  // mutex_.lock();
  // std::unique_lock<std::mutex> l(mutex_);
  // std::cout << "[Msg] IdGenerator::ReleaseId() 11 id = " << id << std::endl;
  if (id > 0 && is_id_used_->at(id)) {
    // std::cout << "[Msg] IdGenerator::ReleaseId() 22 id = " << id
    //           << "  id_queue_ size = " << id_queue_->size()
    //           << " is_id_used_->at(id)" << is_id_used_->at(id) << std::endl;
    id_queue_->emplace_back(id);
    is_id_used_->at(id) = false;
  } else {
    std::string str = "IdGenerator: Release ID: " + std::to_string(id) +
                      "  is Not In IdGenerator!";
    throw std::runtime_error(str);
  }

  // std::cout << "[Msg] IdGenerator::ReleaseId() 33 id = " << id << std::endl;
  // mutex_.unlock();
}

/* vim: set ts=2 sw=2 sts=2 tw=100 et: */
